#!/usr/bin/python3
# -*- coding: utf-8 -*-

# 类和实例

# 让内部属性不被外部访问，可以把属性的名称前加上两个下划线__，在Python中，实例的变量名如果以__开头，就变成了一个私有变量（private），只有内部可以访问，外部不能访问
class Student(object):
	def __init__(self, name, score):
		self.__name = name
		self.__score = score
	def get_grade(self):
		return '名字：'+self.__name+';'+'成绩：'+str(self.__score)

bart = Student('小明', 78)
bart2 = Student('小米', 88)

print(bart.get_grade())
print(bart2.get_grade())

# 需要注意的是，在Python中，变量名类似__xxx__的，也就是以双下划线开头，并且以双下划线结尾的，是特殊变量，
# 特殊变量是可以直接访问的，不是private变量，所以，不能用__name__、__score__这样的变量名。
# 有些时候，你会看到以一个下划线开头的实例变量名，比如_name，这样的实例变量外部是可以访问的，但是，
# 按照约定俗成的规定，当你看到这样的变量时，意思就是，“虽然我可以被访问，但是，请把我视为私有变量，不要随意访问”。
# 双下划线开头的实例变量是不是一定不能从外部访问呢？其实也不是。
# 不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name，
# 所以，仍然可以通过_Student__name来访问__name变量：

bart._Student__name = '哈哈'
print(bart._Student__name)
print(bart.get_grade())

# 最后注意下面的这种错误写法：
# 表面上看，外部代码“成功”地设置了__name变量，但实际上这个__name变量和class内部的__name变量不是一个变量！
# 内部的__name变量已经被Python解释器自动改成了_Student__name，而外部代码给bart新增了一个__name变量。
bart.__name = '哈哈2'
print(bart.__name)



# 但是，如果我们想要限制实例的属性怎么办？比如，只允许对Student实例添加name和age属性。
class Student(object):
	__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

s = Student() # 创建新的实例
s.name = 'Michael' # 绑定属性'name'
s.age = 25 # 绑定属性'age'
# s.score = 99 # 绑定属性'score'